package cn.ii8080.i8.gateway.server.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.ReactiveAuthenticationManagerAdapter;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.expression.OAuth2ExpressionUtils;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.web.server.WebFilter;
import reactor.core.publisher.Mono;

import java.util.Iterator;

@Configuration
public class CustomSecurityConfig {


    /**
     * token载入
     */
    @Autowired
    private TokenAuthenticationConverter tokenAuthenticationConverter;
       /**
     * token校验
     */
    @Bean
    public ReactiveAuthenticationManager reactiveAuthenticationManager() {
        return new ReactiveAuthenticationManagerAdapter((authentication) -> {

            if (authentication instanceof OAuth2Authentication) {
                OAuth2Authentication gmAccountAuthentication = (OAuth2Authentication) authentication;
                if (gmAccountAuthentication.getPrincipal() != null) {
                    authentication.setAuthenticated(true);
                    return authentication;
                } else {
                    return authentication;
                }
            } else {
                return authentication;
            }
        });
    }

    /**
     * 范围权限校验
     *
     * @param scopesStr
     * @return
     */
    public ReactiveAuthorizationManager<AuthorizationContext> hasScopes(final String scopesStr) {
        final String[] scopes = scopesStr.split(",");
        return new ReactiveAuthorizationManager<AuthorizationContext>() {
            @Override
            public Mono<AuthorizationDecision> check(Mono<Authentication> authenticationMono, AuthorizationContext object) {
                return authenticationMono.map(authentication -> {
                    return new AuthorizationDecision(OAuth2ExpressionUtils.hasAnyScope(authentication, scopes));
                }).defaultIfEmpty(new AuthorizationDecision(false));
            }
        };
    }


    /**
     * 主要过滤配置类
     *
     * @param http
     * @return
     */
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
                .authorizeExchange()
                .pathMatchers("/auth/**").permitAll()
                .pathMatchers("/resource/product/list").permitAll()//.access("scope_1")  //无需进行权限过滤的请求路径
                .pathMatchers("/resource/product/test").permitAll()
                .pathMatchers("/resource/product/admin").hasRole("ADMIN")
                .pathMatchers("/resource/product/test").access(hasScopes("scope_2"))
                .pathMatchers("/resource/product/test").access(hasScopes("scope_1"))
                .anyExchange().authenticated()
                .and()
                .httpBasic()
                .and()
                .formLogin().disable()//关闭表单登录
                .csrf().disable()//必须支持跨域
                .logout().disable();//关闭退出登录
        SecurityWebFilterChain chain = http.build();
        Iterator<WebFilter> weIterable = chain.getWebFilters().toIterable().iterator();
        while (weIterable.hasNext()) {
            WebFilter f = weIterable.next();
            if (f instanceof AuthenticationWebFilter) {
                AuthenticationWebFilter webFilter = (AuthenticationWebFilter) f;
                //将自定义的AuthenticationConverter添加到过滤器中
                webFilter.setServerAuthenticationConverter(tokenAuthenticationConverter);
            }
        }
        return chain;

    }

}